package main

import (
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/recover"
	"log"
	"os"
	"os/signal"
	"shopx/app/caches"
	"shopx/app/models"
	"shopx/config"
	"shopx/routes"
)

type App struct {
	*fiber.App

	//DB *gorm.DB
	//Rdb *redis.Client
	//Hasher  hashing.Driver
	//Session *session.Session
}

// register middleware
func (app *App) registerMiddlewares(config *config.Config) {

	// Middleware - Custom Access Logger based on zap
	//if config.GetBool("MW_ACCESS_LOGGER_ENABLED") {
	//	app.Use(middleware.AccessLogger(&middleware.AccessLoggerConfig{
	//		Type:        config.GetString("MW_ACCESS_LOGGER_TYPE"),
	//		Environment: config.GetString("APP_ENV"),
	//		Filename:    config.GetString("MW_ACCESS_LOGGER_FILENAME"),
	//		MaxSize:     config.GetInt("MW_ACCESS_LOGGER_MAXSIZE"),
	//		MaxAge:      config.GetInt("MW_ACCESS_LOGGER_MAXAGE"),
	//		MaxBackups:  config.GetInt("MW_ACCESS_LOGGER_MAXBACKUPS"),
	//		LocalTime:   config.GetBool("MW_ACCESS_LOGGER_LOCALTIME"),
	//		Compress:    config.GetBool("MW_ACCESS_LOGGER_COMPRESS"),
	//	}))
	//}
	//
	//// Middleware - Force HTTPS
	//if config.GetBool("MW_FORCE_HTTPS_ENABLED") {
	//	app.Use(middleware.ForceHTTPS())
	//}

	// Middleware - Force trailing slash
	//if config.GetBool("MW_FORCE_TRAILING_SLASH_ENABLED") {
	//	app.Use(middleware.ForceTrailingSlash())
	//}

	// Middleware - HSTS
	//if config.GetBool("MW_HSTS_ENABLED") {
	//	app.Use(middleware.HSTS(&middleware.HSTSConfig{
	//		MaxAge:            config.GetInt("MW_HSTS_MAXAGE"),
	//		IncludeSubdomains: config.GetBool("MW_HSTS_INCLUDESUBDOMAINS"),
	//		Preload:           config.GetBool("MW_HSTS_PRELOAD"),
	//	}))
	//}

	// Middleware - Suppress WWW
	//if config.GetBool("MW_SUPPRESS_WWW_ENABLED") {
	//	app.Use(middleware.SuppressWWW())
	//}
	//
	//// Middleware - Recover
	//if config.GetBool("MW_FIBER_RECOVER_ENABLED") {
	//	app.Use(recover.New())
	//}

	// TODO: Middleware - Basic Authentication

	// Middleware - Cache
	//if config.GetBool("MW_FIBER_CACHE_ENABLED") {
	//	app.Use(cache.New(cache.Config{
	//		Expiration:   config.GetDuration("MW_FIBER_CACHE_EXPIRATION"),
	//		CacheControl: config.GetBool("MW_FIBER_CACHE_CACHECONTROL"),
	//	}))
	//}
	//
	//// Middleware - Compress
	//if config.GetBool("MW_FIBER_COMPRESS_ENABLED") {
	//	app.Use(compress.New(compress.Config{
	//		Level: compress.Level(0),
	//	}))
	//}
	//
	//// Middleware - CORS
	//if config.GetBool("MW_FIBER_CORS_ENABLED") {
	//	app.Use(cors.New(cors.Config{
	//		AllowOrigins:     config.GetString("MW_FIBER_CORS_ALLOWORIGINS"),
	//		AllowMethods:     config.GetString("MW_FIBER_CORS_ALLOWMETHODS"),
	//		AllowHeaders:     config.GetString("MW_FIBER_CORS_ALLOWHEADERS"),
	//		AllowCredentials: config.GetBool("MW_FIBER_CORS_ALLOWCREDENTIALS"),
	//		ExposeHeaders:    config.GetString("MW_FIBER_CORS_EXPOSEHEADERS"),
	//		MaxAge:           config.GetInt("MW_FIBER_CORS_MAXAGE"),
	//	}))
	//}
	//
	//// Middleware - CSRF
	//if config.GetBool("MW_FIBER_CSRF_ENABLED") {
	//	app.Use(csrf.New(csrf.Config{
	//		TokenLookup: config.GetString("MW_FIBER_CSRF_TOKENLOOKUP"),
	//		Cookie: &fiber.Cookie{
	//			Name:     config.GetString("MW_FIBER_CSRF_COOKIE_NAME"),
	//			SameSite: config.GetString("MW_FIBER_CSRF_COOKIE_SAMESITE"),
	//		},
	//		CookieExpires: config.GetDuration("MW_FIBER_CSRF_COOKIE_EXPIRES"),
	//		ContextKey:    config.GetString("MW_FIBER_CSRF_CONTEXTKEY"),
	//	}))
	//}
	//
	//// Middleware - ETag
	//if config.GetBool("MW_FIBER_ETAG_ENABLED") {
	//	app.Use(etag.New(etag.Config{
	//		Weak: config.GetBool("MW_FIBER_ETAG_WEAK"),
	//	}))
	//}
	//
	//// Middleware - Expvar
	//if config.GetBool("MW_FIBER_EXPVAR_ENABLED") {
	//	app.Use(expvar.New())
	//}
	//
	//// Middleware - Favicon
	//if config.GetBool("MW_FIBER_FAVICON_ENABLED") {
	//	app.Use(favicon.New(favicon.Config{
	//		File:         config.GetString("MW_FIBER_FAVICON_FILE"),
	//		CacheControl: config.GetString("MW_FIBER_FAVICON_CACHECONTROL"),
	//	}))
	//}
	//
	//// TODO: Middleware - Filesystem
	//
	//// Middleware - Limiter
	//if config.GetBool("MW_FIBER_LIMITER_ENABLED") {
	//	app.Use(limiter.New(limiter.Config{
	//		Max:      config.GetInt("MW_FIBER_LIMITER_MAX"),
	//		Duration: config.GetDuration("MW_FIBER_LIMITER_DURATION"),
	//		// TODO: Key
	//		// TODO: LimitReached
	//	}))
	//}
	//
	//// Middleware - Monitor
	//if config.GetBool("MW_FIBER_MONITOR_ENABLED") {
	//	app.Use(monitor.New())
	//}
	//
	//// Middleware - Pprof
	//if config.GetBool("MW_FIBER_PPROF_ENABLED") {
	//	app.Use(pprof.New())
	//}
	//
	//// TODO: Middleware - Proxy
	//
	//// Middleware - RequestID
	//if config.GetBool("MW_FIBER_REQUESTID_ENABLED") {
	//	app.Use(requestid.New(requestid.Config{
	//		Header: config.GetString("MW_FIBER_REQUESTID_HEADER"),
	//		// TODO: Generator
	//		ContextKey: config.GetString("MW_FIBER_REQUESTID_CONTEXTKEY"),
	//	}))
	//}

	// TODO: Middleware - Timeout
}

// Stop the Fiber application
func (app *App) exit() {
	_ = app.Shutdown()
}

func main() {

	// 配置初始化
	cfg := config.New()

	// DB初始化
	err := models.New(&models.DBConfig{
		Driver:   cfg.GetString("DB_DRIVER"),
		Host:     cfg.GetString("DB_HOST"),
		Port:     cfg.GetInt("DB_PORT"),
		Username: cfg.GetString("DB_USERNAME"),
		Password: cfg.GetString("DB_PASSWORD"),
		Database: cfg.GetString("DB_DATABASE"),
	})
	if err != nil {
		log.Fatal(err)
	}

	//Redis初始化
	caches.New(&caches.RedisConfig{
		Address:  cfg.GetString("REDIS_HOST"),
		Password: cfg.GetString("REDIS_PASSWORD"),
		DB:       cfg.GetInt("REDIS_DB"),
	})

	// App 初始化
	app := App{
		App: fiber.New(*cfg.GetFiberConfig()),
		//DB:  models.DB,
		//Rdb: caches.Rdb,
		//Hasher:  hashing.New(cfg.GetHasherConfig()),
		//Session: session.New(cfg.GetSessionConfig()),
	}
	app.Use(recover.New())

	app.registerMiddlewares(cfg)

	// Register web routes
	web := app.Group("")
	routes.Web(web)

	// Register application API routes (using the /api/v1 group)
	api := app.Group("/api")
	apiv1 := api.Group("/v1")
	routes.Api(apiv1)

	// Register static routes for the public directory
	app.Static("/", "./public")

	// Custom 404 Handler
	app.Use(func(c *fiber.Ctx) error {
		if err := c.SendStatus(fiber.StatusNotFound); err != nil {
			panic(err)
		}
		if err := c.Render("errors/404", fiber.Map{}); err != nil {
			return c.Status(fiber.StatusInternalServerError).SendString(err.Error())
		}
		return err
	})

	// Close any connections on interrupt signal
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		<-c
		app.exit()
	}()

	// Start listening on the specified address
	err = app.Listen(cfg.GetString("APP_ADDR"))
	if err != nil {
		app.exit()
	}
}
